#include <QDebug>
#include "modulemanager.h"
#include "portmanager.h"

#include "modulehplcpump.h"
#include "protocol/hplc/qinfine/common/hplcqinfinefindpacket.h"
#include "protocol/hplc/qinfine/detector/hplcqinfinedetectorprotocol.h"
#include "protocol/hplc/qinfine/pump/hplcqinfinepumpprotocol.h"
#include "protocol/hplc/qinfine/collector/hplcqinfinecollectorprotocol.h"
#include "protocol/hplc/zkys/common/hplczkysfindpacket.h"
#include "protocol/hplc/zkys/pump/hplczkyspumpprotocol.h"

#include "modulehplcautosampler.h"
#include "protocol/hplc/sparklink/hplcsparklinkfindpacket.h"
#include "protocol/hplc/sparklink/autosampler/hplcsparklinkautosamplerprotocol.h"
#include "protocol/hplc/sparklink/autosampler/hplcsparklinkautosamplerdeviceprotocol.h"

#include "modulehplctimeprogram.h"

#include "flowmetersli1000.h"

#include "simplefoccontroller.h"
#include "simplefocfindpacket.h"
#include "simplefocprotocol.h"

#include "moduleelectronicscalelichen.h"
#include "electronicscale/lichen/lichenfindpacket.h"
#include "electronicscale/lichen/lichenprotocol.h"

#include "moduleelectronicscaleshimadzu.h"
#include "electronicscale/shimadzu/shimadzufindpacket.h"
#include "electronicscale/shimadzu/shimadzuprotocol.h"

#include "application.h"
#include <QThread>
#include <QVariant>
#include <QMetaType>

SINGLETON_IMPLIMENT(ModuleManager)

ModuleManager::ModuleManager(QObject *parent)
    : BaseManager (parent)
{
    qDebug() << "ModuleManager...";
    m_mutex = new QMutex(QMutex::Recursive);

    qRegisterMetaType<QVariant>("QVariant");

    qDebug() << "ModuleManager...completed";
}

ModuleManager::~ModuleManager()
{
    delete m_mutex;
}

bool ModuleManager::attach(BaseModule *module)
{
    QMutexLocker locker(m_mutex);
    if (module == nullptr)
        return false;
    qDebug() << "attach module : " << module->getName();

    if (m_modules.contains(module->getMagic()))
    {
        qWarning() << "attach module(" << module->getName() << ") failed, because repeat magic";
        return false;
    }

    m_modules.insert(module->getMagic(), module);

    module->moveToThread(thread()); // 移到module线程

    return true;
}

bool ModuleManager::detach(BaseModule *module)
{
    QMutexLocker locker(m_mutex);
    if (module == nullptr)
        return false;
    qDebug() << "detach module : " << module->getName();

    if (!m_modules.contains(module->getMagic()))
        return false;

    m_modules.remove(module->getMagic());
    return true;
}

BaseModule *ModuleManager::find(const QString &name)
{
    QMutexLocker locker(m_mutex);
    foreach(auto p, m_modules)
    {
        if (p->getName() == name)
        {
            return p;
        }
    }
    return nullptr;
}

BaseModule *ModuleManager::find(ModuleID id)
{
    QMutexLocker locker(m_mutex);
    foreach(auto p, m_modules)
    {
        if (p->getID() == id)
        {
            return p;
        }
    }
    return nullptr;
}

BaseModule *ModuleManager::find(uint magic)
{
    QMutexLocker locker(m_mutex);
    if (m_modules.contains(magic))
        return m_modules.value(magic);
    return nullptr;
}

void ModuleManager::print()
{
    QMutexLocker locker(m_mutex);
    qDebug() << "===========Print All Modules==============";
    int i = 0;
    foreach (auto m, m_modules)
    {
        qDebug() << i << ", " << m->getName();
        i++;
    }
    qDebug() << "===========End All Modules==============";
}

void ModuleManager::onStart()
{
    QMutexLocker locker(m_mutex);
    qDebug() << "ModuleManager onStart...";

    initHplcPump();
    initHplcDetector();
//    initHplcCollector();
//    initHplcAutoSampler();
    initTimeProgram();

//    initFlowmeter();
//    initSimpleFocController();

    initLiChenElectronicSacle();
    initShimadzuElectronicSacle();

    qDebug() << "ModuleManager onStart...completed";
}

void ModuleManager::customEvent(QEvent *event)
{
    quint16 id = event->type();
    switch (id)
    {
        case EV_Test:
            qDebug() << "EV_Test";
        break;
        default:
            BaseManager::customEvent(event);
        break;
    }
}

void ModuleManager::initHplcPump()
{
    for (int i = 0; i < 4; i++)
    {
        // init module
        ModuleHplcPump *hplcPump = new ModuleHplcPump();
        hplcPump->setID((ModuleID)(ModuleID::ModuleID_HPLC_PumpA + i));
        hplcPump->setName(QString("HPLC Pump %1").arg(QChar('A' + i)));

        // connect port
        BasePort *port =  portManager->find(PortID_PumpA + i);
        if (port == nullptr)
        {
            hplcPump->deleteLater();
            continue;
        }
        hplcPump->setPort(port);

#if 0
        // init protocol
        hplc::qinfine::HplcQinfinePumpProtocol *hplcPumpProtocol
                = new hplc::qinfine::HplcQinfinePumpProtocol(*hplcPump->getParam(), hplcPump);
        hplcPumpProtocol->setName(QString("HPLC Pump %1 Protocol").arg(QChar('A' + i)));
        hplcPump->setProtocol(hplcPumpProtocol);

        if (!attach(hplcPump))
        {
            hplcPump->deleteLater();
            hplcPumpProtocol->deleteLater();
        }
        else
        {
            // Protocol finder init
            hplc::qinfine::HplcQinfineFindPacket *finder = new hplc::qinfine::HplcQinfineFindPacket();
            finder->setName(QString("HPLC Pump %1 Protocol Finder").arg(QChar('A' + i)));
            port->setFinder(finder);

            hplcPump->onStart();
        }
#else
        // init protocol
        hplc::zkys::HplcZkysPumpProtocol *hplcPumpProtocol
                = new hplc::zkys::HplcZkysPumpProtocol(*hplcPump->getParam(), hplcPump);
        hplcPumpProtocol->setName(QString("HPLC Pump %1 Protocol").arg(QChar('A' + i)));
        hplcPump->setProtocol(hplcPumpProtocol);

        if (!attach(hplcPump))
        {
            hplcPump->deleteLater();
            hplcPumpProtocol->deleteLater();
        }
        else
        {
            // Protocol finder init
            hplc::zkys::HplcZkysFindPacket *finder = new hplc::zkys::HplcZkysFindPacket();
            finder->setName(QString("HPLC Pump %1 Protocol Finder").arg(QChar('A' + i)));
            port->setFinder(finder);

            hplcPump->onStart();
        }
#endif
    }
}

void ModuleManager::initHplcDetector()
{
    // init module
    ModuleHplcDetector *module = new ModuleHplcDetector();
    module->setID((ModuleID)(ModuleID::ModuleID_HPLC_Detector));
    module->setName(QString("HPLC Detector"));

    // connect port
    BasePort *port =  portManager->find(PortID_Detector);
    if (port == nullptr)
    {
        module->deleteLater();
        return;
    }
    module->setPort(port);

#if 1
    // init protocol
    hplc::qinfine::HplcQinfineDetectorProtocol *protocol
            = new hplc::qinfine::HplcQinfineDetectorProtocol(*module->getParam(), module);
    protocol->setName(QString("HPLC Detector Protocol"));
    module->setProtocol(protocol);

    if (!attach(module))
    {
        module->deleteLater();
        protocol->deleteLater();
    }
    else
    {
        // Protocol finder init
        hplc::qinfine::HplcQinfineFindPacket *finder = new hplc::qinfine::HplcQinfineFindPacket();
        finder->setName(QString("HPLC Detector Protocol Finder"));
        port->setFinder(finder);

        module->onStart();
    }
#else
    // init protocol
    hplc::zkys::HplcZkysPumpProtocol *protocol
            = new hplc::zkys::HplcZkysPumpProtocol(*module->getParam(), module);
    protocol->setName(QString("HPLC Detector Protocol"));
    module->setProtocol(protocol);

    if (!attach(module))
    {
        module->deleteLater();
        protocol->deleteLater();
    }
    else
    {
        // Protocol finder init
        hplc::zkys::HplcZkysFindPacket *finder = new hplc::zkys::HplcZkysFindPacket();
        finder->setName(QString("HPLC Detector Protocol Finder"));
        port->setFinder(finder);

        module->onStart();
    }
#endif
}

void ModuleManager::initHplcCollector()
{

}

void ModuleManager::initHplcAutoSampler()
{
    // hplc autosampler
//    if (0)
    {
        // init module
        ModuleHplcAutoSampler *hplcAutoSampler = new ModuleHplcAutoSampler();
        hplcAutoSampler->setID(ModuleID::ModuleID_HPLC_AutoSampler);
        hplcAutoSampler->setName(QString("HPLC AutoSampler"));

        // connect port
        BasePort *port =  portManager->find(PortID_Main);
        if (port != nullptr)
            hplcAutoSampler->setPort(port);

        // init protocol
        hplc::sparklink::HplcSparkLinkAutoSamplerProtocol *hplcSparkLinkAutoSamplerProtocol
                = new hplc::sparklink::HplcSparkLinkAutoSamplerProtocol(*hplcAutoSampler->getParam(), hplcAutoSampler);
        hplcSparkLinkAutoSamplerProtocol->setName("HPLC SparkLink AutoSampler Protocol");
        hplcAutoSampler->setProtocol(hplcSparkLinkAutoSamplerProtocol);

        if (!attach(hplcAutoSampler))
        {
            hplcAutoSampler->deleteLater();
            hplcSparkLinkAutoSamplerProtocol->deleteLater();
        }
        else
        {
            if (port != nullptr)
            {
                // Protocol finder init
                hplc::sparklink::HplcSparkLinkFindPacket *finder = new hplc::sparklink::HplcSparkLinkFindPacket();
                finder->setName(QString("HPLC SparkLink Protocol Finder"));
                port->setFinder(finder);
            }

            hplcAutoSampler->onStart();
        }
    }

    // hplc autosampler device
//    if (0)
    {
        // init module
        ModuleHplcAutoSampler *hplcAutoSamplerDevice = new ModuleHplcAutoSampler();
        hplcAutoSamplerDevice->setID(ModuleID::ModuleID_HPLC_AutoSampler_Device);
        hplcAutoSamplerDevice->setName(QString("HPLC AutoSampler Device"));

        // connect port
        BasePort *port =  portManager->find(PortID_Debug);
        if (port != nullptr)
            hplcAutoSamplerDevice->setPort(port);

        // init protocol
        hplc::sparklink::HplcSparkLinkAutoSamplerDeviceProtocol *hplcSparkLinkAutoSamplerDeviceProtocol
                = new hplc::sparklink::HplcSparkLinkAutoSamplerDeviceProtocol(*hplcAutoSamplerDevice->getParam(), hplcAutoSamplerDevice);
        hplcSparkLinkAutoSamplerDeviceProtocol->setName("HPLC SparkLink AutoSampler Device Protocol");
        hplcAutoSamplerDevice->setProtocol(hplcSparkLinkAutoSamplerDeviceProtocol);

        if (!attach(hplcAutoSamplerDevice))
        {
            hplcAutoSamplerDevice->deleteLater();
            hplcSparkLinkAutoSamplerDeviceProtocol->deleteLater();
        }
        else
        {
            if (port != nullptr)
            {
                // Protocol finder init
                hplc::sparklink::HplcSparkLinkFindPacket *finder = new hplc::sparklink::HplcSparkLinkFindPacket();
                finder->setName(QString("HPLC SparkLink Device Protocol Finder"));
                port->setFinder(finder);
            }

            hplcAutoSamplerDevice->onStart();
        }
    }

}

void ModuleManager::initTimeProgram()
{
    BaseModule *mod;
    mod = moduleManager->find(ModuleID_HPLC_PumpA);
    if (mod == nullptr)
        return;
    mod = moduleManager->find(ModuleID_HPLC_PumpB);
    if (mod == nullptr)
        return;
    mod = moduleManager->find(ModuleID_HPLC_PumpC);
    if (mod == nullptr)
        return;
    mod = moduleManager->find(ModuleID_HPLC_PumpD);
    if (mod == nullptr)
        return;
    mod = moduleManager->find(ModuleID_HPLC_Detector);
    if (mod == nullptr)
        return;

    ModuleHplcTimeProgram *module = new ModuleHplcTimeProgram();
    module->setID(ModuleID_HPLC_TimeProgram);
    module->setName(QString("Hplc Time Program"));

    if (!attach(module))
    {
        module->deleteLater();
    }
    module->onStart();
}

void ModuleManager::initFlowmeter()
{
    // init module
    FlowmeterSLI1000 *flowmeter = new FlowmeterSLI1000();
    flowmeter->setID(ModuleID::ModuleID_FlowMeterSLI1000);
    flowmeter->setName(QString("Flowmeter SLI-1000"));

    if (!attach(flowmeter))
    {
        flowmeter->deleteLater();
    }
    flowmeter->onStart();
}

void ModuleManager::initSimpleFocController()
{
    // init module
    SimpleFOCController *simpleFOCController = new SimpleFOCController();
    simpleFOCController->setID(ModuleID::ModuleID_SimpleFOCController);
    simpleFOCController->setName(QString("Simple FOC Module"));

    // connect port
    BasePort *port =  portManager->find(PortID_Main);
    if (port != nullptr)
        simpleFOCController->setPort(port);

    // init protocol
    SimpleFOCProtocol *simpleFOCProtocol = new SimpleFOCProtocol(simpleFOCController);
    simpleFOCProtocol->setName("Simple FOC Protocol");
    simpleFOCController->setProtocol(simpleFOCProtocol);

    if (!attach(simpleFOCController))
    {
        simpleFOCController->deleteLater();
        simpleFOCProtocol->deleteLater();
    }
    else
    {
        if (port != nullptr)
        {
            // Protocol finder init
            SimpleFOCFindPacket *finder = new SimpleFOCFindPacket();
            finder->setName(QString("Simple FOC Protocol Finder"));
            port->setFinder(finder);
        }
    }
}

void ModuleManager::initLiChenElectronicSacle()
{
    // init module
    ModuleElectronicScaleLiChen *module = new ModuleElectronicScaleLiChen();
    module->setID(ModuleID::ModuleID_ElectronicScale_LiChen);
    module->setName(QString("LiChen ElectronicScale Module"));

    // connect port
    BasePort *port =  portManager->find(PortID_ElectronicScale_LiChen);
    if (port != nullptr)
        module->setPort(port);

    // init protocol
    LiChenProtocol *protocol = new LiChenProtocol(module->param(), module);
    protocol->setName("LiChen ElectronicScale Protocol");
    module->setProtocol(protocol);

    if (!attach(module))
    {
        module->deleteLater();
        protocol->deleteLater();
    }
    else
    {
        if (port != nullptr)
        {
            // Protocol finder init
            LiChenFindPacket *finder = new LiChenFindPacket();
            finder->setName(QString("LiChen ElectronicScale Protocol Finder"));
            port->setFinder(finder);
        }
    }
}

void ModuleManager::initShimadzuElectronicSacle()
{
    // init module
    ModuleElectronicScaleShimadzu *module = new ModuleElectronicScaleShimadzu();
    module->setID(ModuleID::ModuleID_ElectronicScale_Shimadzu);
    module->setName(QString("Shimadzu ElectronicScale Module"));

    // connect port
    BasePort *port =  portManager->find(PortID_ElectronicScale_Shimadzu);
    if (port != nullptr)
        module->setPort(port);

    // init protocol
    ShimadzuProtocol *protocol = new ShimadzuProtocol(module->param(), module);
    protocol->setName("Shimadzu ElectronicScale Protocol");
    module->setProtocol(protocol);

    if (!attach(module))
    {
        module->deleteLater();
        protocol->deleteLater();
    }
    else
    {
        if (port != nullptr)
        {
            // Protocol finder init
            ShimadzuFindPacket *finder = new ShimadzuFindPacket();
            finder->setName(QString("Shimadzu ElectronicScale Protocol Finder"));
            port->setFinder(finder);
        }
    }
}
